#!/usr/bin/env python3
"""
Phase 2: Unified Scorecard
Extract key coefficients from all papers' output tables into one master table.
Table 2: One row per major finding across 12 papers, with 69c vs 140c comparison.
"""

import sys
import pandas as pd
import numpy as np
from pathlib import Path

PROJECT_DIR = Path("/mnt/c/demographics_capital_flows")
TABLE_DIR = PROJECT_DIR / "fragility" / "output" / "tables"
TABLE_DIR.mkdir(parents=True, exist_ok=True)

print("=" * 70)
print("PHASE 2: UNIFIED SCORECARD")
print("=" * 70)

# ════════════════════════════════════════════════════════════════════════════
# Master scorecard: manually curated from PAPER_SUMMARIES.md + output tables
# Each row is a major finding across the portfolio
# ════════════════════════════════════════════════════════════════════════════

scorecard = [
    # --- Paper 1: Multilateral Foundation ---
    {
        'paper': '1. Multilateral',
        'finding': 'Z₁ → CA/GDP (baseline)',
        'coef_69': 29.1, 'p_69': 0.103, 'sig_69': '',
        'coef_140': 19.0, 'p_140': 0.238, 'sig_140': '',
        'change_pct': -34.7, 'category': 'Magnitude-attenuated',
        'note': 'Significant only in parsimonious spec (38.4, p=0.017)',
    },
    {
        'paper': '1. Multilateral',
        'finding': 'Z₁×KAOPEN → CA/GDP',
        'coef_69': 38.9, 'p_69': 0.004, 'sig_69': '***',
        'coef_140': 21.6, 'p_140': 0.051, 'sig_140': '*',
        'change_pct': -44.5, 'category': 'Magnitude-attenuated',
        'note': 'Joint test still p<0.001; Z₁×KAOPEN marginal',
    },
    # --- Paper 2: Gravity Bilateral ---
    {
        'paper': '2. Gravity Bilateral',
        'finding': 'Rate-mediated share of bilateral',
        'coef_69': 58.0, 'p_69': np.nan, 'sig_69': '',
        'coef_140': 23.0, 'p_140': np.nan, 'sig_140': '',
        'change_pct': -60.3, 'category': 'Magnitude-attenuated',
        'note': 'Channel decomposition revised; 77% direct quantity',
    },
    # --- Paper 3: Causal Identification ---
    {
        'paper': '3. Causal ID',
        'finding': 'CCA tipping point (drop 13 countries)',
        'coef_69': np.nan, 'p_69': np.nan, 'sig_69': '',
        'coef_140': np.nan, 'p_140': 0.400, 'sig_140': '',
        'change_pct': np.nan, 'category': 'Influential observations',
        'note': 'Z₁ collapses from p<0.001 to p=0.40 dropping 13 CCA',
    },
    # --- Paper 4: Capital Deepening ---
    {
        'paper': '4. Capital Deepening',
        'finding': 'Z₁ → I/Y (investment effort)',
        'coef_69': 39.0, 'p_69': 0.006, 'sig_69': '***',
        'coef_140': 32.3, 'p_140': 0.006, 'sig_140': '***',
        'change_pct': -17.2, 'category': 'Robust',
        'note': 'Survives expansion; F-stat improved 6→28',
    },
    {
        'paper': '4. Capital Deepening',
        'finding': 'Z₁ → ΔK/L (capital deepening)',
        'coef_69': 0.25, 'p_69': 0.007, 'sig_69': '***',
        'coef_140': -0.04, 'p_140': 0.453, 'sig_140': '',
        'change_pct': -116.0, 'category': 'Sign-reversed',
        'note': 'OECD +0.25**; non-OECD null; composition effect',
    },
    {
        'paper': '4. Capital Deepening',
        'finding': 'Rule_of_law × Z interaction',
        'coef_69': 0.003, 'p_69': 0.007, 'sig_69': '***',
        'coef_140': -0.003, 'p_140': 0.007, 'sig_140': '***',
        'change_pct': -200.0, 'category': 'Sign-reversed',
        'note': 'Strong institutions → financial not physical capital',
    },
    # --- Paper 5: Asset Returns ---
    {
        'paper': '5. Asset Returns',
        'finding': 'Z₁ → 10y bond yield',
        'coef_69': 58.5, 'p_69': 0.004, 'sig_69': '***',
        'coef_140': 43.7, 'p_140': 0.015, 'sig_140': '**',
        'change_pct': -25.3, 'category': 'Robust',
        'note': 'Murder-suicide confirmed; survives GDP/pc horse race',
    },
    {
        'paper': '5. Asset Returns',
        'finding': 'old_dep / youth_dep magnitudes',
        'coef_69': -16.6, 'p_69': 0.001, 'sig_69': '***',
        'coef_140': -8.3, 'p_140': 0.005, 'sig_140': '***',
        'change_pct': -50.0, 'category': 'Magnitude-attenuated',
        'note': 'Story intact but age-structure coefficients ~halved',
    },
    # --- Paper 6: Japanification ---
    {
        'paper': '6. Japanification',
        'finding': 'Z₁ → Japanification index',
        'coef_69': 0.86, 'p_69': 0.049, 'sig_69': '*',
        'coef_140': 1.18, 'p_140': 0.003, 'sig_140': '***',
        'change_pct': 37.2, 'category': 'Robust (strengthened)',
        'note': 'Baseline strengthened; channel decomposition reversed',
    },
    {
        'paper': '6. Japanification',
        'finding': 'Growth channel → inflation channel',
        'coef_69': np.nan, 'p_69': 0.001, 'sig_69': '***',
        'coef_140': np.nan, 'p_140': 0.560, 'sig_140': '',
        'change_pct': np.nan, 'category': 'Channel-reversed',
        'note': 'Growth channel null; inflation -3.25*** now dominant',
    },
    # --- Paper 7: Fiscal Dominance ---
    {
        'paper': '7. Fiscal Dominance',
        'finding': 'Expenditure-revenue asymmetry',
        'coef_69': 2.5, 'p_69': 0.001, 'sig_69': '***',
        'coef_140': 3.3, 'p_140': 0.001, 'sig_140': '***',
        'change_pct': 32.0, 'category': 'Robust (strengthened)',
        'note': '3.3:1 ratio; nearly perfect replication',
    },
    {
        'paper': '7. Fiscal Dominance',
        'finding': 'Bohn fiscal reaction coefficient',
        'coef_69': 0.006, 'p_69': 0.043, 'sig_69': '**',
        'coef_140': 0.006, 'p_140': 0.060, 'sig_140': '*',
        'change_pct': 0.0, 'category': 'Robust',
        'note': 'Near-identical to 69c estimate',
    },
    # --- Paper 8: Crises ---
    {
        'paper': '8. Crises',
        'finding': 'old_dep → banking crisis risk',
        'coef_69': -0.10, 'p_69': 0.050, 'sig_69': '*',
        'coef_140': 0.095, 'p_140': 0.035, 'sig_140': '**',
        'change_pct': -195.0, 'category': 'Sign-reversed',
        'note': 'Protective→risky in non-OECD; low-income <$4,840',
    },
    {
        'paper': '8. Crises',
        'finding': 'old_dep → CA reversal (protective)',
        'coef_69': -0.54, 'p_69': 0.001, 'sig_69': '***',
        'coef_140': -0.59, 'p_140': 0.001, 'sig_140': '***',
        'change_pct': 9.3, 'category': 'Robust',
        'note': 'CA reversal protection preserved',
    },
    # --- Paper 9: Extensions ---
    {
        'paper': '9. Extensions',
        'finding': 'Z₁ → income balance',
        'coef_69': 53.0, 'p_69': 0.001, 'sig_69': '***',
        'coef_140': 41.4, 'p_140': 0.001, 'sig_140': '***',
        'change_pct': -21.9, 'category': 'Robust',
        'note': 'Attenuated 22% but still strongly significant',
    },
    {
        'paper': '9. Extensions',
        'finding': 'Z₁ → ΔKAOPEN (prediction)',
        'coef_69': np.nan, 'p_69': 0.057, 'sig_69': '*',
        'coef_140': np.nan, 'p_140': 0.122, 'sig_140': '',
        'change_pct': np.nan, 'category': 'Collapsed',
        'note': 'Marginal→insignificant',
    },
    # --- Paper 10: Trilemma ---
    {
        'paper': '10. Trilemma',
        'finding': 'Z₁ → peg-vs-float (logit)',
        'coef_69': 10.53, 'p_69': 0.001, 'sig_69': '***',
        'coef_140': 0.79, 'p_140': 0.040, 'sig_140': '**',
        'change_pct': -92.5, 'category': 'Collapsed',
        'note': '13× attenuation; OECD-specific (Z₁=3.14**)',
    },
    {
        'paper': '10. Trilemma',
        'finding': 'Z₁ → MI (monetary independence)',
        'coef_69': 2.73, 'p_69': 0.001, 'sig_69': '***',
        'coef_140': 0.14, 'p_140': 0.800, 'sig_140': '',
        'change_pct': -94.9, 'category': 'Collapsed',
        'note': 'OECD-specific; null globally',
    },
    {
        'paper': '10. Trilemma',
        'finding': 'Eurozone amplification (Z_dev)',
        'coef_69': -214.0, 'p_69': 0.001, 'sig_69': '***',
        'coef_140': -185.5, 'p_140': 0.001, 'sig_140': '***',
        'change_pct': -13.3, 'category': 'Robust',
        'note': '18× vs floaters; survived and reframed',
    },
    # --- Paper 11: Automation ---
    {
        'paper': '11. Automation',
        'finding': 'Z×KAOPEN → capital intensity',
        'coef_69': np.nan, 'p_69': 0.010, 'sig_69': '***',
        'coef_140': np.nan, 'p_140': 0.500, 'sig_140': '',
        'change_pct': np.nan, 'category': 'Collapsed',
        'note': 'OECD p<0.01; non-OECD null; OECD-only phenomenon',
    },
    {
        'paper': '11. Automation',
        'finding': 'Z₁ → I/Y (automation paper)',
        'coef_69': 39.0, 'p_69': 0.006, 'sig_69': '***',
        'coef_140': 32.3, 'p_140': 0.006, 'sig_140': '***',
        'change_pct': -17.2, 'category': 'Robust',
        'note': 'Stable across samples',
    },
    # --- Paper 12: Net/Gross ---
    {
        'paper': '12. Net/Gross',
        'finding': 'KAOPEN sign-flip on CA',
        'coef_69': 14.9, 'p_69': 0.050, 'sig_69': '*',
        'coef_140': 5.4, 'p_140': 0.300, 'sig_140': '',
        'change_pct': -63.8, 'category': 'Collapsed',
        'note': 'Lost significance in expanded panel',
    },
    {
        'paper': '12. Net/Gross',
        'finding': 'Gross positions (winsorized)',
        'coef_69': 471.0, 'p_69': 0.050, 'sig_69': '**',
        'coef_140': np.nan, 'p_140': 0.480, 'sig_140': '',
        'change_pct': np.nan, 'category': 'Collapsed',
        'note': 'Only FX reserves robust (Z₁=63-67***)',
    },
    {
        'paper': '12. Net/Gross',
        'finding': 'OECD → any external balance',
        'coef_69': np.nan, 'p_69': 0.010, 'sig_69': '***',
        'coef_140': np.nan, 'p_140': 0.500, 'sig_140': '',
        'change_pct': np.nan, 'category': 'Subsample-null',
        'note': 'Complete OECD null on all measures',
    },
    {
        'paper': '12. Net/Gross',
        'finding': 'S-I suppression ratio',
        'coef_69': 15.0, 'p_69': np.nan, 'sig_69': '',
        'coef_140': 15.0, 'p_140': np.nan, 'sig_140': '',
        'change_pct': 0.0, 'category': 'Robust',
        'note': 'S-I masking mechanism preserved',
    },
]

sc_df = pd.DataFrame(scorecard)
sc_df.to_csv(TABLE_DIR / "table2_unified_scorecard.csv", index=False)

# ════════════════════════════════════════════════════════════════════════════
# Summary by category
# ════════════════════════════════════════════════════════════════════════════
print("\n" + "=" * 70)
print("FRAGILITY TAXONOMY SUMMARY")
print("=" * 70)

cats = sc_df['category'].value_counts()
for cat, count in cats.items():
    findings = sc_df[sc_df['category'] == cat]['finding'].tolist()
    print(f"\n{cat} ({count}):")
    for f in findings:
        print(f"  - {f}")

# ════════════════════════════════════════════════════════════════════════════
# Markdown Table 2
# ════════════════════════════════════════════════════════════════════════════
md = ["# Table 2: Unified Fragility Scorecard\n"]
md.append("Each row is a major empirical finding across 12 papers on demographics and capital flows.\n")
md.append("| Paper | Finding | Coef (69c) | p (69c) | Coef (140c) | p (140c) | Change | Category |")
md.append("|:---|:---|---:|---:|---:|---:|---:|:---|")

for _, r in sc_df.iterrows():
    c69 = f"{r['coef_69']:.1f}{r['sig_69']}" if pd.notna(r['coef_69']) else "—"
    p69 = f"{r['p_69']:.3f}" if pd.notna(r['p_69']) else "—"
    c140 = f"{r['coef_140']:.1f}{r['sig_140']}" if pd.notna(r['coef_140']) else "—"
    p140 = f"{r['p_140']:.3f}" if pd.notna(r['p_140']) else "—"
    chg = f"{r['change_pct']:+.0f}%" if pd.notna(r['change_pct']) else "—"
    md.append(f"| {r['paper']} | {r['finding']} | {c69} | {p69} | {c140} | {p140} | {chg} | {r['category']} |")

# Category summary
md.append(f"\n## Fragility Taxonomy\n")
md.append(f"| Category | Count | Description |")
md.append(f"|:---|---:|:---|")
md.append(f"| Robust | {len(sc_df[sc_df['category'].str.contains('Robust')])} | Survives or strengthens with expansion |")
md.append(f"| Magnitude-attenuated | {len(sc_df[sc_df['category']=='Magnitude-attenuated'])} | Same sign, weaker magnitude (>20% change) |")
md.append(f"| Collapsed | {len(sc_df[sc_df['category']=='Collapsed'])} | Significant → insignificant |")
md.append(f"| Sign-reversed | {len(sc_df[sc_df['category']=='Sign-reversed'])} | Coefficient changes sign across samples |")
md.append(f"| Channel-reversed | {len(sc_df[sc_df['category']=='Channel-reversed'])} | Dominant mechanism shifts to different channel |")
md.append(f"| Subsample-null | {len(sc_df[sc_df['category']=='Subsample-null'])} | Entire subsample shows no signal |")
md.append(f"| Influential observations | {len(sc_df[sc_df['category']=='Influential observations'])} | Small group of countries drives result |")

md.append(f"\n## Notes\n")
for _, r in sc_df.iterrows():
    if r['note']:
        md.append(f"- **{r['finding']}**: {r['note']}")

md_text = "\n".join(md)
(TABLE_DIR / "table2_unified_scorecard.md").write_text(md_text)
print(f"\n{md_text}")

print(f"\nSaved: table2_unified_scorecard.csv and .md")
print("Phase 2 complete.")
